package http3

import (
	"context"
	"crypto/tls"
	"fmt"
	"net"
	"net/http"
	"sync"
	"time"

	"github.com/quic-go/quic-go"
	"github.com/quic-go/quic-go/http3"
)

type HTTP3Server struct {
	server    *http3.Server
	handler   http.Handler
	tlsConfig *tls.Config
	quicConf  *quic.Config
	addr      string
	mu        sync.RWMutex
	metrics   *HTTP3Metrics
}

type HTTP3Metrics struct {
	ActiveConnections int64
	TotalRequests     int64
	ErrorCount        int64
}

func NewHTTP3Server(addr string, handler http.Handler, certFile, keyFile string) (*HTTP3Server, error) {
	cert, err := tls.LoadX509KeyPair(certFile, keyFile)
	if err != nil {
		return nil, fmt.Errorf("failed to load certificates: %v", err)
	}

	tlsConfig := &tls.Config{
		Certificates: []tls.Certificate{cert},
		NextProtos:   []string{"h3"},
	}

	quicConfig := &quic.Config{
		MaxIdleTimeout:  30000,
		KeepAlivePeriod: 15000,
		EnableDatagrams: true,
	}

	s := &HTTP3Server{
		handler:   handler,
		tlsConfig: tlsConfig,
		quicConf:  quicConfig,
		addr:      addr,
		metrics:   &HTTP3Metrics{},
	}

	s.server = &http3.Server{
		TLSConfig: tlsConfig,
		Handler:   s.metricsMiddleware(handler),
		Addr:      addr,
	}

	return s, nil
}

func (s *HTTP3Server) metricsMiddleware(next http.Handler) http.Handler {
	return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		s.mu.Lock()
		s.metrics.ActiveConnections++
		s.metrics.TotalRequests++
		s.mu.Unlock()

		defer func() {
			s.mu.Lock()
			s.metrics.ActiveConnections--
			s.mu.Unlock()

			if err := recover(); err != nil {
				s.mu.Lock()
				s.metrics.ErrorCount++
				s.mu.Unlock()
				http.Error(w, "Internal Server Error", http.StatusInternalServerError)
			}
		}()

		next.ServeHTTP(w, r)
	})
}

func (s *HTTP3Server) Start() error {
	return s.server.ListenAndServe()
}

func (s *HTTP3Server) ListenAndServe() error {
	udpAddr, err := net.ResolveUDPAddr("udp", s.addr)
	if err != nil {
		return err
	}

	udpConn, err := net.ListenUDP("udp", udpAddr)
	if err != nil {
		return err
	}

	return s.server.Serve(udpConn)
}

func (s *HTTP3Server) Shutdown(ctx context.Context) error {
	return s.server.Close()
}

func (s *HTTP3Server) GetMetrics() *HTTP3Metrics {
	s.mu.RLock()
	defer s.mu.RUnlock()
	return &HTTP3Metrics{
		ActiveConnections: s.metrics.ActiveConnections,
		TotalRequests:     s.metrics.TotalRequests,
		ErrorCount:        s.metrics.ErrorCount,
	}
}

type HTTP3Transport struct {
	*http3.Transport
	maxIdleConns    int
	idleConnTimeout int
}

func NewHTTP3Transport(maxIdleConns, idleConnTimeout int) *HTTP3Transport {
	return &HTTP3Transport{
		Transport: &http3.Transport{
			TLSClientConfig: &tls.Config{
				InsecureSkipVerify: true,
			},
			QUICConfig: &quic.Config{
				MaxIdleTimeout:  time.Duration(30) * time.Second,
				KeepAlivePeriod: time.Duration(15) * time.Second,
				EnableDatagrams: true,
			},
		},
		maxIdleConns:    maxIdleConns,
		idleConnTimeout: idleConnTimeout,
	}
}
